﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GameObjectPool {

	private string poolName;
	private GameObject poolObjectPrefab;
	private Transform poolRoot;
	private List<GameObject> availableList = new List<GameObject> ();
	private List<GameObject> usedList = new List<GameObject> ();
	private int objectCount = 0;

	public GameObjectPool(string poolName, GameObject poolObjectPrefab, int initCount, Transform poolManager) {
		// pool root create
		GameObject poolGameObject = new GameObject ();
		poolGameObject.name = poolName + "Pool";
		poolRoot = poolGameObject.transform;
		poolRoot.SetParent (poolManager);
		poolRoot.transform.localPosition = Vector3.zero;
		poolRoot.transform.localScale = Vector3.one;

		// pool data
		this.poolName = poolName;
		this.poolObjectPrefab = poolObjectPrefab;

		// create initCount elements
		for (int i = 0; i < initCount; ++i) {
			GameObject newObject = NewObjectInstance ();
			availableList.Add (newObject);
		}
	}

	public void DestroySelf() {
		availableList.Clear ();
		usedList.Clear ();

		MonoBehaviour.Destroy (poolRoot);

		// how to deal prefab immediately??? or only wait resrouce unload unused assets.
		// Resources.UnloadAsset(poolObjectPrefab);
		// poolObjectPrefab = null;
		poolObjectPrefab = null;
		poolRoot = null;
	}

	private GameObject NewObjectInstance() {
		++objectCount;
		GameObject newObject = GameObject.Instantiate (poolObjectPrefab) as GameObject;
		newObject.name = poolName + objectCount;
		Reset (newObject);
		return newObject;
	}

	public GameObject GetAvailableObject() {
		//Debug.Log ("Get Pool Available Object");
		GameObject availableObject;
		if (availableList.Count > 0) {
			availableObject = availableList [0];
			availableList.RemoveAt (0);
		} else {
			availableObject = NewObjectInstance ();
		}

		usedList.Add (availableObject);
		availableObject.SetActive (true);
		return availableObject;
	}

	public void ReturnObjectToPool(GameObject returnObject) {
		int usedIndex = -1;
		for (int i = 0; i < usedList.Count; ++i) {
			if (returnObject == usedList [i]) {
				usedIndex = i;
				break;
			}
		}

		if (usedIndex >= 0) {
			usedList.RemoveAt (usedIndex);
			availableList.Add (returnObject);
			Reset (returnObject);
			returnObject.SetActive (false);
		} else {
			Debug.Log ("Return to wrong pool! GameObject name is " + returnObject.name);
		}
	}

	private void Reset(GameObject go) {
		go.transform.SetParent (poolRoot);
		go.transform.localScale = Vector3.one;
		go.transform.eulerAngles = Vector3.zero;
		go.transform.localPosition = Vector3.zero;
	}
}
